package com.bjtu.ptsite.service.impl;


import com.bjtu.ptsite.mapper.PeerMapper;
import com.bjtu.ptsite.mapper.UserMapper;
import com.bjtu.ptsite.model.AnnounceRequest;
import com.bjtu.ptsite.model.PeerMessage;
import com.bjtu.ptsite.model.User;
import com.bjtu.ptsite.service.PromotionService;
import com.bjtu.ptsite.service.UserService;
import com.bjtu.ptsite.tracker.entity.TrackerMessage;
import com.bjtu.ptsite.mapper.TrackerMessageMapper;
import com.bjtu.ptsite.utils.InfoHashUtil;
import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.bcodec.BEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static net.i2p.crypto.eddsa.Utils.bytesToHex;

/**
 *
 * @author Zehao Wang, Junjie Zhang, Yutao Wei
 *
 */
@Service
@Slf4j
public class AnnounceService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TrackerMessageMapper trackerMessageMapper;

    @Autowired
    private PeerService peerService;

    @Autowired
    private UserService userService;

    @Autowired
    private PeerMapper peerMapper;

    @Autowired
    private PromotionService promotionService;

    private static final String EVENT_STOPPED = "stopped";
    private static final String DEFAULT_DOWNLOAD_DISCOUNT = "1.0";

    /**
     * 处理announce请求，添加事务失败回滚
     * @param passKey
     * @param announceRequest
     * @param clientIp
     * @param queryString
     * @return
     */
    @Transactional(rollbackFor = Exception.class) // 添加rollbackFor属性确保事务回滚
    public byte[] handleAnnounce(String passKey, AnnounceRequest announceRequest, String clientIp, String queryString) {
        try {
            // 解析请求信息
            parseAnnounceRequest(announceRequest, passKey, queryString);

            // 验证用户和种子信息
            User user = validateUser(passKey);
            if (user == null) {
                log.error("未找到用户信息，passKey: {}", passKey);
                return null;
            }

            TrackerMessage trackerMessage = validateTorrent(announceRequest.getInfoHashHex());
            if (trackerMessage == null) {
                log.info("未找到种子信息，infohash: {}", announceRequest.getInfoHashHex());
                return null;
            }

            // 更新Peer信息
            PeerMessage peerMessage = updatePeerMessage(announceRequest, clientIp);

            // 设置默认下载折扣
            if (trackerMessage.getDownloadDiscount() == null) {
                trackerMessage.setDownloadDiscount(DEFAULT_DOWNLOAD_DISCOUNT);
            }

            // 计算流量变化和积分
            long uploadedDelta = calculateUploadedDelta(announceRequest, peerMessage, trackerMessage);
            long downloadedDelta = calculateDownloadedDelta(announceRequest, peerMessage, trackerMessage);

            // 更新用户积分和流量
            updateUserPointsAndTraffic(user, uploadedDelta, downloadedDelta);

            // 获取活跃Peer列表
            Date fiveMinutesAgo = new Date(System.currentTimeMillis() - 15 * 60 * 1000);
            List<PeerMessage> peerMessages = peerMapper.selectPeerMessageList(announceRequest.getInfoHashHex(), fiveMinutesAgo);

            // 构建响应
            int interval = 1800;
            return buildAnnounceResponse(peerMessages, interval);
        } catch (Exception e) {
            log.error("处理 Announce 请求时发生错误", e);
            return null;
        }
    }

    /**
     * 解析Announce请求参数
     */
    private void parseAnnounceRequest(AnnounceRequest announceRequest, String passKey, String queryString) throws Exception {
        byte[] infoHash = InfoHashUtil.matchInfoHash(queryString);
        announceRequest.setPassKey(passKey);
        announceRequest.setInfoHashBytes(infoHash);
        announceRequest.setInfoHashHex(bytesToHex(infoHash));

        if(announceRequest.getEvent()==null||announceRequest.getEvent().isBlank()){
            announceRequest.setSeeder(announceRequest.getLeft() == 0);
        }else{
            announceRequest.setSeeder(false);
        }

        String peerId1 = announceRequest.getPeer_id();
        if (peerId1 != null) {
            announceRequest.setPeer_id(URLDecoder.decode(peerId1, "ISO-8859-1"));
        }
    }

    /**
     * 验证用户信息
     */
    private User validateUser(String passKey) {
        return userMapper.selectByPasskey(passKey);
    }

    /**
     * 验证种子信息
     */
    private TrackerMessage validateTorrent(String hexInfoHash) {
        promotionService.applyPromotionRules(hexInfoHash);
        return trackerMessageMapper.selectByInfoHash(hexInfoHash);
    }

    /**
     * 更新Peer信息
     */
    private PeerMessage updatePeerMessage(AnnounceRequest announceRequest, String clientIp) {
        String hexInfoHash = announceRequest.getInfoHashHex();
        String peerId = announceRequest.getPeer_id();
        long uploaded = announceRequest.getUploaded();
        long downloaded = announceRequest.getDownloaded();
        long left = announceRequest.getLeft();
        String event = announceRequest.getEvent();
        int port = announceRequest.getPort();
        boolean flag = EVENT_STOPPED.equals(event) ? false : announceRequest.getSeeder();

        PeerMessage peerMessage = peerMapper.selectByPassKey(
                announceRequest.getPassKey(),
                hexInfoHash,
                peerId,
                clientIp,
                port
        );

        Long oldDownload = 0L;
        Long oldUpload = 0L;

        if (peerMessage == null) {
            peerMessage = PeerMessage.builder()
                    .peerId(peerId)
                    .uploaded(uploaded)
                    .downloaded(downloaded)
                    .peerLeft(left)
                    .port(port)
                    .ip(clientIp)
                    .lastAnnounceTime(LocalDateTime.now())
                    .event(event)
                    .passkey(announceRequest.getPassKey())
                    .infoHash(hexInfoHash)
                    .isSeeder(flag)
                    .build();
            peerMapper.insertPeerMessage(peerMessage);
        } else {
            oldDownload = peerMessage.getDownloaded();
            oldUpload = peerMessage.getUploaded();
            peerMessage.setUploaded(uploaded);
            peerMessage.setDownloaded(downloaded);
            peerMessage.setPeerLeft(left);
            peerMessage.setPort(port);
            peerMessage.setIp(clientIp);
            peerMessage.setLastAnnounceTime(LocalDateTime.now());
            peerMessage.setEvent(event);
            peerMessage.setSeeder(flag);
            peerMapper.updatePeerMessage(peerMessage);
        }

        return peerMessage;
    }

    /**
     * 计算上传流量增量
     */
    private long calculateUploadedDelta(AnnounceRequest announceRequest, PeerMessage peerMessage, TrackerMessage trackerMessage) {
        return (long) (Math.max(0, Math.abs(announceRequest.getUploaded() - peerMessage.getUploaded()))
                * trackerMessage.getUploadMultiplier());
    }

    /**
     * 计算下载流量增量
     */
    private long calculateDownloadedDelta(AnnounceRequest announceRequest, PeerMessage peerMessage, TrackerMessage trackerMessage) {
        return (long) (Math.max(0, Math.abs(announceRequest.getDownloaded() - peerMessage.getDownloaded()))
                * Double.parseDouble(trackerMessage.getDownloadDiscount()));
    }

    /**
     * 更新用户积分和流量
     */
    private void updateUserPointsAndTraffic(User user, long uploadedDelta, long downloadedDelta) {
        int points = (int) Math.sqrt(uploadedDelta);
        log.info("用户 {} 获得积分: {}", user.getUsername(), points);

        if (user.getSeedPoints() <= Math.sqrt(Integer.MAX_VALUE - points)) {
            user.setSeedPoints(user.getSeedPoints() + points);
        }

        userService.updateUserTraffic(user.getPassKey(), uploadedDelta, downloadedDelta);
        userService.updateUserTraffic2(user);
    }

    /**
     * 生成种子文件
     * @param peerMessages peer 信息
     * @param interval 间隔时间
     * @return 种子文件
     * @throws Exception 异常
     */
    public byte[] buildAnnounceResponse(List<PeerMessage> peerMessages, int interval) throws Exception {
        Map<String, BEValue> response = new HashMap<>(4);

        response.put("interval", new BEValue(interval));

        int complete = 0;
        int incomplete = 0;

        ByteArrayOutputStream peerStream = new ByteArrayOutputStream();

        for (PeerMessage peer : peerMessages) {
            if (peer.getPeerLeft() == 0) {
                complete++;
            } else {
                incomplete++;
            }

            // IP：4字节
            byte[] ipBytes = InetAddress.getByName(peer.getIp()).getAddress();
            peerStream.write(ipBytes);
            // 端口：2字节
            int port = peer.getPort();
            peerStream.write((port >> 8) & 0xFF);
            peerStream.write(port & 0xFF);
        }

        response.put("complete", new BEValue(complete));
        response.put("incomplete", new BEValue(incomplete));
        response.put("peers", new BEValue(peerStream.toByteArray()));

        System.out.println("Announce 返回 repsnse"+response);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BEncoder.bencode(response, baos);

        return baos.toByteArray();
    }

    //垃圾 peer 清理任务	周期性清理 10 分钟以上未汇报的 peer
    //防刷机制 防止同一 peer 重复 announce 刷上传量（配合上传/下载增量校验）
}
